package devil.bo;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;

public class AutoQuery
{
	private Object o = null;
	private Bean bean = null;
	private String alias = null;
	
	private AutoQuery(Object o)
	{
		this.o = o;
		bean = new Bean(o);
		alias = getAlias();
	}
	
	private Query creatQuery(Session session)
	{
		Queue<Integer> notNullObjectsIndex = getNotNullObjectIndexes();
		Query query = session.createQuery(getFormPart()
				+ getWherePart(notNullObjectsIndex));
		for(int i = 0; !notNullObjectsIndex.isEmpty(); ++ i)
		{
			query.setParameter(i,
					bean.getPropertyObjects().get(notNullObjectsIndex.poll()));
		}
		return query;
	}
	
	private String creatHQLWithoutValues(Object o)
	{
		return (new StringBuffer().append(getFormPart())
				.append(getWherePart(getNotNullObjectIndexes()))).toString();
	}
	
	private String creatHQLWithValues(Object o)
	{
		Queue<Integer> notNullObjectsIndex = getNotNullObjectIndexes();
		StringBuffer hql = new StringBuffer(creatHQLWithoutValues(o));
		for(int i = 0; !notNullObjectsIndex.isEmpty();)
		{
			i = hql.indexOf("?");
			hql.replace(
					i,
					i + 1,
					"'"
							+ bean.getPropertyObjects()
									.get(notNullObjectsIndex.poll()).toString()
							+ "'");
		}
		return hql.toString();
	}
	
	private String getWherePart(Queue<Integer> notNullObjectsIndex)
	{
		StringBuffer hql = new StringBuffer();
		if(notNullObjectsIndex.isEmpty())
		{
			return "";
		}
		hql.append(" where ");
		for(Integer index : notNullObjectsIndex)
		{
			hql.append(alias).append(".")
					.append(bean.getPropertyNames().get(index))
					.append("=? and ");
		}
		hql.delete(hql.length() - 5, hql.length());
		return hql.toString();
	}
	
	private String getFormPart()
	{
		return new StringBuffer().append("from ")
				.append(o.getClass().getSimpleName()).append(" ").append(alias)
				.toString();
	}
	
	private boolean hasMethodSize(Object o)
	{
		return hasMethod(o, "size");
	}
	
	private boolean hasMethod(Object o, String methodName)
	{
		for(Method method : o.getClass().getMethods())
		{
			if(method.getName().equals(methodName))
			{
				return true;
			}
		}
		return false;
	}
	
	@SuppressWarnings("unused")
	private boolean isSet(Object o)
	{
		for(Class<?> interfaceClass : o.getClass().getInterfaces())
		{
			if(Set.class.equals(interfaceClass))
			{
				return true;
			}
		}
		return false;
	}
	
	private String getAlias()
	{
		return "_" + o.getClass().getSimpleName().toLowerCase() + "_";
	}
	
	private Queue<Integer> getNotNullObjectIndexes()
	{
		Queue<Integer> notNullObjectsIndex = new LinkedList<Integer>();
		for(int i = 0; i != bean.getPropertyObjects().size(); ++ i)
		{
			if(bean.getPropertyObjects().get(i) != null
					&& !hasMethodSize(bean.getPropertyObjects().get(i)))
			{
				notNullObjectsIndex.add(i);
			}
		}
		return notNullObjectsIndex;
	}
	
	public static Query getQuery(Session session, Object o)
	{
		return new AutoQuery(o).creatQuery(session);
	}
	
	public static String getHQL(Object o)
	{
		return new AutoQuery(o).creatHQLWithValues(o);
	}
}
